pub mod config;
pub mod socks5;
pub mod http;
pub mod forwarding;
pub mod tproxy;
pub mod tun;
pub mod redirect;

use config::ClientConfig;
use hysteria_core::protocol::{AuthRequest, TcpRequest};
use std::sync::Arc;
use tokio::net::TcpListener;
use tracing::{error, info};

pub struct HysteriaClient {
    config: Arc<ClientConfig>,
}

impl HysteriaClient {
    pub fn new(config: ClientConfig) -> Self {
        Self {
            config: Arc::new(config),
        }
    }

    pub async fn serve(&self) -> anyhow::Result<()> {
        info!("Hysteria client starting");

        // Start SOCKS5 proxy if configured
        if let Some(socks5_config) = &self.config.socks5 {
            let client = self.clone_arc();
            let addr = socks5_config.listen;
            tokio::spawn(async move {
                if let Err(e) = client.serve_socks5(addr).await {
                    error!("SOCKS5 server error: {}", e);
                }
            });
            info!("SOCKS5 proxy listening on {}", addr);
        }

        // Start HTTP proxy if configured
        if let Some(http_config) = &self.config.http {
            info!("HTTP proxy listening on {}", http_config.listen);
        }

        // Keep client running
        tokio::signal::ctrl_c().await?;
        info!("Shutting down client");

        Ok(())
    }

    fn clone_arc(&self) -> Arc<Self> {
        Arc::new(Self {
            config: Arc::clone(&self.config),
        })
    }

    async fn serve_socks5(&self, addr: std::net::SocketAddr) -> anyhow::Result<()> {
        let listener = TcpListener::bind(addr).await?;

        loop {
            let (socket, _) = listener.accept().await?;
            let client = self.clone_arc();

            tokio::spawn(async move {
                if let Err(e) = socks5::handle_socks5(socket, client).await {
                    error!("SOCKS5 connection error: {}", e);
                }
            });
        }
    }
}
